Sleep diary is usually given with an actimeter to allow participants to report the subjective evaluation of their sleep episodes. A sleep diary is the easiest and least invasive way to get information about sleep episodes from participants. It allows comparison between data recorded by an actigraph and the real-life.
In medical fields, sleep diary is commonly recommended in order to help doctors in the diagnosis and treatment of sleep-wake cycle disorders.
In [1]:
import pyActigraphy
/usr/local/lib/python3.7/site-packages/statsmodels/tools/_testing.py:19: FutureWarning: pandas.util.testing is deprecated. Use the functions in the public API at pandas.testing instead.
import pandas.util.testing as tm
In [2]:
import os
In [3]:
import plotly.graph_objs as go
In [4]:
# Retrieve path to example files
fpath = os.path.join(os.path.dirname(pyActigraphy.__file__),'tests/data/')
In [5]:
# Read test file
raw = pyActigraphy.io.read_raw_awd(fpath+'example_01.AWD')
In [6]:
# Check the start time of the actigraphy recording
raw.start_time
Out[6]:
Timestamp('1918-01-23 13:58:00')
In [7]:
# Check the duration of the recording
raw.duration()
Out[7]:
Timedelta('12 days 18:41:00')
Sleep diary class has been created to read a sleep diary file. Sleep diary file must be formatted as the following:
SubjectID |
your_subject_id |
|
|---|---|---|
Type |
Start |
End |
Night/Nap/NoWear |
YYYY-MM-DD HH:MM |
YYYY-MM-DD HH:MM |
As an illustration, let us first read the sleep diary of example 01:
In [8]:
sleep_diary = raw.read_sleep_diary(fpath + 'example_01_sleepdiary.ods')
Subject’s name in the sleep diary is easily verified:
In [9]:
raw.sleep_diary.name
Out[9]:
'EXAMPLE_01'
To access to the data contained in the sleep diary:
In [10]:
raw.sleep_diary.diary
Out[10]:
| TYPE | START | END | |
|---|---|---|---|
| 0 | NAP | 1918-01-24 13:00:00 | 1918-01-24 13:45:00 |
| 1 | NIGHT | 1918-01-24 23:00:00 | 1918-01-25 07:00:00 |
| 2 | NAP | 1918-01-25 13:00:00 | 1918-01-25 13:35:00 |
| 3 | NIGHT | 1918-01-25 22:00:00 | 1918-01-26 07:30:00 |
| 4 | NAP | 1918-01-26 13:10:00 | 1918-01-26 14:00:00 |
| 5 | NIGHT | 1918-01-27 00:00:00 | 1918-01-27 07:30:00 |
| 6 | NAP | 1918-01-27 13:00:00 | 1918-01-27 13:45:00 |
| 7 | NIGHT | 1918-01-27 23:20:00 | 1918-01-28 05:00:00 |
| 8 | NOWEAR | 1918-01-28 12:00:00 | 1918-01-28 12:30:00 |
| 9 | NAP | 1918-01-28 16:00:00 | 1918-01-28 17:30:00 |
| 10 | NIGHT | 1918-01-28 22:30:00 | 1918-01-29 06:15:00 |
| 11 | NAP | 1918-01-29 13:15:00 | 1918-01-29 14:00:00 |
| 12 | NIGHT | 1918-01-29 23:20:00 | 1918-01-30 07:00:00 |
| 13 | NAP | 1918-01-30 13:00:00 | 1918-01-30 13:45:00 |
| 14 | NIGHT | 1918-01-30 23:15:00 | 1918-01-31 06:45:00 |
| 15 | NAP | 1918-01-31 13:15:00 | 1918-01-31 14:00:00 |
| 16 | NIGHT | 1918-01-31 23:15:00 | 1918-02-01 07:00:00 |
| 17 | NAP | 1918-02-01 13:00:00 | 1918-02-01 13:45:00 |
| 18 | NOWEAR | 1918-02-01 20:40:00 | 1918-02-01 21:33:00 |
| 19 | NIGHT | 1918-02-01 23:20:00 | 1918-02-02 08:00:00 |
| 20 | NAP | 1918-02-02 13:15:00 | 1918-02-02 14:15:00 |
| 21 | NIGHT | 1918-02-02 23:20:00 | 1918-02-03 07:45:00 |
A summary function is available. It returns the
count/mean/std/min/25%/50%/75%/max of the durations found for each state
in the sleep diary:
In [11]:
raw.sleep_diary.summary()
Out[11]:
| count | mean | std | min | 25% | 50% | 75% | max | |
|---|---|---|---|---|---|---|---|---|
| TYPE | ||||||||
| NAP | 10 | 00:50:30 | 00:15:10.494371 | 00:35:00 | 00:45:00 | 00:45:00 | 00:48:45 | 01:30:00 |
| NIGHT | 10 | 07:50:30 | 00:59:19.353873 | 05:40:00 | 07:32:30 | 07:45:00 | 08:18:45 | 09:30:00 |
| NOWEAR | 2 | 00:41:30 | 00:16:15.807358 | 00:30:00 | 00:35:45 | 00:41:30 | 00:47:15 | 00:53:00 |
The mean and standard deviation for one state is accessible by
state_infos function:
In [12]:
raw.sleep_diary.state_infos('NIGHT')
Out[12]:
(Timedelta('0 days 07:50:30'), Timedelta('0 days 00:59:19.353873'))
Specific functions are implemented to directly estimate the mean and standard deviation for theses states: * bed time * nap time * no wear
In [13]:
raw.sleep_diary.total_bed_time()
Out[13]:
(Timedelta('0 days 07:50:30'), Timedelta('0 days 00:59:19.353873'))
In [14]:
raw.sleep_diary.total_nap_time()
Out[14]:
(Timedelta('0 days 00:50:30'), Timedelta('0 days 00:15:10.494371'))
In [15]:
raw.sleep_diary.total_nowear_time()
Out[15]:
(Timedelta('0 days 00:41:30'), Timedelta('0 days 00:16:15.807358'))
First, create a layout for the plot and then plot data.
Shapes are created for each sleep episodes and are meant to be overlaid with the actimetry data. Different parameters (e.g. colours) enable to distinguish sleep during night-time and nap episode.
All shapes are created from a template:
In [16]:
raw.sleep_diary.shaded_area
Out[16]:
{'type': 'rect',
'xref': 'x',
'yref': 'paper',
'x0': 0,
'y0': 0,
'x1': 1,
'y1': 1,
'fillcolor': '',
'opacity': 0.5,
'layer': 'below',
'line': {'width': 0}}
Then plot actimetry data with the corresponding sleep diary, by adapting the layout:
In [17]:
layout = go.Layout(
title="Actigraphy data",
xaxis=dict(title="Date time"),
yaxis=dict(title="Counts/period"),
shapes=raw.sleep_diary.shapes(),
showlegend=False
)
In [18]:
go.Figure(data=go.Scatter(x=raw.data.index, y=raw.data), layout=layout)
Features of shaded areas can easily be accessed and modified. Three types of modifications are feasible:
Global modifications : change parameters for all shaded areas (by changing the shape template)
One state modifications : change parameters specific for one state
Local modifications : change parameters for the selected shaded area
In [19]:
raw.sleep_diary.shaded_area['opacity'] = 1
In [20]:
layout.update(shapes=raw.sleep_diary.shapes());
In [21]:
go.Figure(data=go.Scatter(x=raw.data.index, y=raw.data), layout=layout)
In [22]:
# Access to colours for each state
raw.sleep_diary.state_colour
Out[22]:
{'NAP': '#7bc043', 'NIGHT': '#d3d3d3', 'NOWEAR': '#ee4035'}
In [23]:
raw.sleep_diary.state_colour['NIGHT'] = 'rgb(140,95,148)'
In [24]:
# Check colour modification
raw.sleep_diary.state_colour
Out[24]:
{'NAP': '#7bc043', 'NIGHT': 'rgb(140,95,148)', 'NOWEAR': '#ee4035'}
In [25]:
layout.update(shapes=raw.sleep_diary.shapes());
In [26]:
go.Figure(data=go.Scatter(x=raw.data.index, y=raw.data), layout=layout)
In [27]:
shapes = raw.sleep_diary.shapes()
shapes[0]['fillcolor'] = 'rgb(0,255,200)'
In [28]:
layout.update(shapes=shapes);
In [29]:
go.Figure(data=go.Scatter(x=raw.data.index, y=raw.data), layout=layout)
For conveniency, four states (active, nap, night, nowear) are automatically implemented when a sleep diary is read. However, the pyActigraphy package allows users to customise colours and to add states.
In [30]:
# Default implemented states
raw.sleep_diary.state_index
Out[30]:
{'ACTIVE': 2, 'NAP': 1, 'NIGHT': 0, 'NOWEAR': -1}
To add a custom state, all indices and their colours have to be specified during the reading of the sleep diary:
In [31]:
raw.read_sleep_diary(
fpath + 'example_01_sleepdiary_extra_states.ods',
state_index=dict(ACTIVE=2, NAP=1, NIGHT=0, NOWEAR=-1, AWAKE_IN_BED=3),
state_colour=dict(
NAP='#7bc043',
NIGHT='#d3d3d3',
NOWEAR='#ee4035',
AWAKE_IN_BED='rgb(143, 19, 131)'
)
)
In [32]:
layout = go.Layout(
title="Actigraphy data",
xaxis=dict(title="Date time"),
yaxis=dict(title="Counts/period"),
shapes=raw.sleep_diary.shapes(),
showlegend=False)
In [33]:
go.Figure(data=go.Scatter(x=raw.data.index, y=raw.data), layout=layout)
Mean and standard deviation for the added state are now also accessible:
In [34]:
raw.sleep_diary.state_infos('AWAKE_IN_BED')
Out[34]:
(Timedelta('0 days 01:30:00'), NaT)
Et voilà! Easy, isn’t it?